﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Pixysoft.Collections
{
    public class MostRecentlyUsedList<T> : IEnumerable<T>, IEnumerator<T>
    {
        int m_max = 50;
        DoubleLinkedList<T> m_list = new DoubleLinkedList<T>();
        List<DoubleLinkedList<T>.LinkItem> list = new List<DoubleLinkedList<T>.LinkItem>();

        /// <summary>
        /// Default constructor for the most recently used items using the default size (50)
        /// </summary>
        public MostRecentlyUsedList()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        /// <summary>
        /// Construct a most recently used items list with the maximum number of items
        /// allowed in the list.
        /// </summary>
        /// <param name="maxItems">Maximum number of items allowed</param>
        public MostRecentlyUsedList(int maxItems)
        {
            m_max = maxItems;
        }

        public List<T> this[string key]
        {
            get
            {
                List<T> rlist = new List<T>();

                foreach (DoubleLinkedList<T>.LinkItem item in list)
                {
                    if (!item.Key.Equals(key))
                        continue;

                    rlist.Add(item.Item);

                    m_list.MoveToHead(item);
                }

                return rlist;
            }
            set
            {
                Add(key, value.ToArray());
            }
        }

        public ICollection<string> Keys
        {
            get
            {
                List<string> rlist = new List<string>();

                foreach (DoubleLinkedList<T>.LinkItem item in list)
                {
                    if (!rlist.Contains(item.Key))
                        rlist.Add(item.Key);
                }

                return rlist;
            }
        }

        public void Add(string key, params T[] values)
        {
            if (string.IsNullOrEmpty(key))
                return;

            foreach (T value in values)
            {
                DoubleLinkedList<T>.LinkItem link = m_list.Prepend(key, value);

                list.Add(link);
            }

            OnInsert();
        }

        public bool Contains(string key)
        {
            return this[key].Count > 0;
        }

        public void Remove(string key)
        {
            List<DoubleLinkedList<T>.LinkItem> rlist = new List<DoubleLinkedList<T>.LinkItem>();

            foreach (DoubleLinkedList<T>.LinkItem item in list)
            {
                if (!item.Key.Equals(key))
                    continue;

                rlist.Add(item);
            }

            foreach (DoubleLinkedList<T>.LinkItem item in rlist)
            {
                m_list.RemoveLink(item);

                list.Remove(item);
            }
        }

        public void Remove(T value)
        {
            List<DoubleLinkedList<T>.LinkItem> rlist = new List<DoubleLinkedList<T>.LinkItem>();

            foreach (DoubleLinkedList<T>.LinkItem item in list)
            {
                if (item.Item.Equals(value))
                    rlist.Add(item);
            }

            foreach (DoubleLinkedList<T>.LinkItem item in rlist)
            {
                m_list.RemoveLink(item);

                list.Remove(item);
            }
        }


        private void OnInsert()
        {
            while (list.Count > m_max)
            {
                // Purge an item from the cache
                DoubleLinkedList<T>.LinkItem tail = m_list.TailLink;

                if (tail != null)
                {
                    string cacheKey = tail.Key;

                    if (string.IsNullOrEmpty(cacheKey))
                    {
                        m_list.RemoveLink(tail);

                        list.Remove(tail);
                    }
                    else
                    {
                        Remove(cacheKey);
                    }
                }
            }
        }

        /// <summary>
        /// The maximum capacity of the list
        /// </summary>
        public int Capacity
        {
            get { return m_max; }
            set
            {
                if (Capacity < 1)
                    throw new Exception("Negative number!");
                m_max = value;
            }
        }

        public int Count
        {
            get
            {
                return list.Count;
            }
        }

        public void Clear()
        {
            m_list.Clear();
            list.Clear();
        }

        public override string ToString()
        {
            StringBuilder buff = new StringBuilder(Convert.ToInt32(m_max));

            buff.Append("[");

            foreach (object item in m_list)
            {
                if (buff.Length > 1)
                    buff.Append(", ");

                buff.Append(item.ToString());
            }

            buff.Append("]");

            return buff.ToString();
        }



        int index = -1;

        public IEnumerator<T> GetEnumerator()
        {
            return this;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this;
        }

        public T Current
        {
            get { return list[index].Item; }
        }

        public void Dispose()
        {
            Reset();
        }

        object System.Collections.IEnumerator.Current
        {
            get { return list[index].Item; }
        }

        public bool MoveNext()
        {
            if (index >= list.Count - 1)
                return false;

            index++;

            return true;
        }

        public void Reset()
        {
            index = -1;
        }
    }
}
